home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994…tember: Reference Library / Dev.CD Sep 94.toast / Periodicals / develop / develop Issue 15 / develop 15 code / Symmetry & Tiles / Tiler Code / Group1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1994-05-27  |  25.6 KB  |  990 lines  |  [TEXT/KAHL]

  1. #include     <graphics libraries.h>
  2. #include     <graphics toolbox.h>
  3. #include     <offscreen library.h>
  4. #include     "SymmetryUtils.h"
  5. #include    "TileConstants.h"
  6. #include    "TileProtos.h"
  7. #include     "Group1.h"
  8.  
  9. extern gxPatternRecord    gPattern;        // The pattern that we fill the window with
  10. extern gxShape            gTileShape;        // The shape that the pattern repeats
  11. extern dragger            gDragger;        // A record containing a manipulable contour & associated stuff
  12. extern gxShape            gOpShapes[];    // Group of shapes to show the
  13.                                         // symmetry operations
  14. extern gxViewPort        gViewPort;
  15. extern Boolean            gContRedraw, gKeepClosed;
  16.  
  17. ///////////////////////////////////////////////////////////////////////////////////
  18. //    Group p1
  19.  
  20. // Test for a hit on an op shape, tracking the drag and returning true
  21. // if one was hit, false otherwise
  22. Boolean    p1_OpShapeHit(gxPoint *clickPt)
  23. {
  24.     gxHitTestInfo    hitStats;
  25.     gxShape            hitShape, oldShape;
  26.     gxTransform        xForm;
  27.     long            shapeNum;
  28.     
  29.     // Test the two translators for a hit
  30.     for(shapeNum = 0; shapeNum < 2; shapeNum++)
  31.     {
  32.         hitShape = gOpShapes[shapeNum];
  33.         xForm = GXGetShapeTransform(hitShape);
  34.         
  35.         // Test only for a hit on the end cap
  36.         GXIgnoreGraphicsNotice(attributes_already_set);
  37.         GXSetTransformHitTest(xForm, gxEndCapPart, kHitTolerance);
  38.         GXPopGraphicsNotice();
  39.             
  40.         // If shape was hit, we're done looking
  41.         if(GXHitTestShape(hitShape, clickPt, &hitStats))
  42.             break;
  43.     }
  44.     
  45.     // If a shape was hit, track it
  46.     if(shapeNum < 2)
  47.     {
  48.         gxLine        theLine;
  49.         gxPoint        anchor, pt, lastPt = *clickPt;;
  50.         
  51.         hitShape = gOpShapes[shapeNum];
  52.         
  53.         // Get the "anchor" point (the tail of the arrow)
  54.         GXGetLine(hitShape, &theLine);
  55.         anchor = theLine.first;
  56.         
  57.         // Create a shape for saving the old position
  58.         if(!gContRedraw)
  59.             oldShape = GXCopyToShape(nil, hitShape);
  60.  
  61.         // Follow the drag around
  62.         while(StillDown())
  63.         {
  64.             // Get the new mouse position and if it's different,
  65.             // adjust the dragged shape
  66.             GXGetViewPortMouse(gViewPort, &pt);
  67.             if(pt.x != lastPt.x || pt.y != lastPt.y)
  68.             {
  69.                 // Save old shape so we can erase and draw in rapid succession
  70.                 if(!gContRedraw)
  71.                 {
  72.                     GXCopyToShape(oldShape, hitShape);
  73.                     
  74.                     // If constraints are on, erase the dragger before.
  75.                     if(gKeepClosed)
  76.                         EraseAShape(gDragger.snake1);
  77.                 }
  78.                 
  79.                 // Move it
  80.                 p1_DragOpShape(hitShape, &pt, &anchor);
  81.                 
  82.                 if(gContRedraw)
  83.                 {
  84.                     // Reset pattern and draw it right now
  85.                     p1_ChangeLattice();
  86.                       OffToScreen();
  87.                 }
  88.                   else
  89.                   {
  90.                     // Erase and draw
  91.                     EraseAShape(oldShape);
  92.                     GXDrawShape(hitShape);
  93.                     
  94.                     // If constraints are on, draw the dragger too.
  95.                     if(gKeepClosed)
  96.                         GXDrawShape(gDragger.snake1);
  97.                   }
  98.               }
  99.             lastPt = pt;
  100.         }
  101.         if(!gContRedraw)
  102.         {
  103.             p1_ChangeLattice(); // Update the pattern
  104.             GXDisposeShape(oldShape);
  105.         }
  106.         return true;
  107.     }
  108.     else // no shape hit
  109.         return false;
  110. }
  111.  
  112. // Moves the op shape and dragger as appropriate
  113. void    p1_DragOpShape(gxShape dragShape, gxPoint *clickPt, gxPoint *anchor)
  114. {
  115.     fixed    xd = clickPt->x - anchor->x, yd = clickPt->y - anchor->y,
  116.             lxd = labs(clickPt->x - anchor->x), lyd = labs(clickPt->y - anchor->y);
  117.     gxPoint    temp;
  118.     gxLine    theLine;
  119.     
  120.     // Get the current line
  121.     GXGetLine(dragShape, &theLine);
  122.  
  123.     // If the point is in bounds, just use it
  124.     if(lxd < kMaxDistance && lyd < kMaxDistance &&
  125.         (lyd > kMinDistance || lxd > kMinDistance) )
  126.     {
  127.         theLine.last = *clickPt;
  128.     }
  129.     else  // Constrain it to the bounds
  130.     {
  131.         temp = *clickPt;
  132.         if( lxd > kMaxDistance )
  133.             temp.x = anchor->x + ( (xd < 0) ? -kMaxDistance : kMaxDistance);
  134.         else if( lxd < kMinDistance )
  135.             temp.x = anchor->x + ( (xd < 0) ? -kMinDistance : kMinDistance);
  136.         
  137.         if( lyd > kMaxDistance )
  138.             temp.y = anchor->y + ( (yd < 0) ? -kMaxDistance : kMaxDistance);
  139.         else if( lyd < kMinDistance )
  140.             temp.y = anchor->y + ( (yd < 0) ? -kMinDistance : kMinDistance);
  141.         
  142.         theLine.last = temp;
  143.     }
  144.     
  145.     // Set the new geometry
  146.     GXSetLine(dragShape, &theLine);
  147.     
  148.     // If constraints are on, adjust the dragger too
  149.     if(gKeepClosed)
  150.     {
  151.         long    slaveIndex;
  152.         
  153.         slaveIndex = (dragShape == gOpShapes[0]) ? gDragger.slavePt[0] : gDragger.slavePt[2];
  154.         GXSetShapePoints(gDragger.snake1, slaveIndex, 1, &theLine.last);
  155.     }        
  156. }
  157.  
  158. // Called either to set the default shapes when resetting the tile, or when 
  159. // the symmetry has changed, to convert one lattice type to another.
  160. // Currently only resets to default
  161. void     p1_RemakeOpShapes(Boolean useDefaults)
  162. {
  163.     gxShape    tempShape;
  164.     gxLine    aLine;
  165.     
  166.     if(true /* useDefaults */)
  167.     {
  168.         tempShape = MakeOpShape(transOp);
  169.         GXMoveShape(tempShape, kStartingOffset, kStartingOffset);
  170.         gOpShapes[0] = GXCopyToShape(nil, tempShape);
  171.         gOpShapes[1] = tempShape;
  172.         GXGetLine(gOpShapes[1], &aLine);
  173.         aLine.last.x = aLine.first.x + kStartingGridSize;
  174.         aLine.last.y = aLine.first.y;
  175.         GXSetLine(gOpShapes[1], &aLine);
  176.     }
  177.     else
  178.     {
  179.         // Look at gPattern to determine the lattice, build new op shapes accordingly
  180.     }
  181. }
  182.  
  183. // Set the dragger to the default shape
  184. void    p1_SetDefaultDragger(gxShape snake)
  185. {
  186.     long        dragPoly[] = {    1,    // number of contours
  187.                                 3,    // number of points
  188.                                 ff(0), ff(64),
  189.                                 ff(0), ff(0),
  190.                                 ff(64), ff(0)    };
  191.                 
  192.  
  193.     // make the starting drag shape
  194.     GXSetPolygons(snake, (gxPolygons *) dragPoly);
  195.     GXMoveShape(snake, kStartingOffset, kStartingOffset);
  196.     
  197.     // Reset the pattern to match the op shapes
  198.     p1_ChangeLattice();
  199. }
  200.  
  201. // Reset the pattern vectors according to the positions of the op shapes
  202. void    p1_ChangeLattice(void)
  203. {
  204.     gxLine    line1, line2;
  205.  
  206.     // Adjust points to define the true unit cell.
  207.     // We just get the vectors direct from the shapes
  208.     GXGetLine(gOpShapes[0], &line2);
  209.     gPattern.v.x = line2.last.x - line2.first.x;
  210.     gPattern.v.y = line2.last.y - line2.first.y;
  211.     GXGetLine(gOpShapes[1], &line1);
  212.     gPattern.u.x = line1.last.x - line1.first.x;
  213.     gPattern.u.y = line1.last.y - line1.first.y;
  214.     
  215.     // Now remake the pattern according to the new lattice and draw it offscreen
  216.     RemakeTile();
  217. }
  218.  
  219. // Repeat the dragger geometry as necessary to build up the full unit cell
  220. //void    p1_BuildCellShape(gxShape snake)
  221. //{
  222. //}    *** Not needed, since the geometry isn't repeated in p1 ***
  223.  
  224.  
  225. // Force the dragger to describe a closed tile
  226. void    p1_AttachConstraints(void)
  227. {
  228.     long    numPts;
  229.     gxLine    line1, line2;
  230.  
  231.     // Get the 2 lines
  232.     GXGetLine(gOpShapes[0], &line1);
  233.     GXGetLine(gOpShapes[1], &line2);
  234.     
  235.     // Get the number of points in the snake
  236.     numPts = GXCountShapePoints(gDragger.snake1, 1);
  237.     if(numPts < 3)
  238.     {
  239.         // There can't be only one point, so there must be 2. 
  240.         // so we just need to add 1 point to the end of the snake
  241.         
  242.         gxPoint    newPt[] = {1L, 1L, 0, 0};    // A polygons structure with 1 point
  243.         
  244.         // Get the point into our poly structure
  245.         GXGetShapePoints(gDragger.snake1, numPts, 1, &newPt[1]);
  246.  
  247.         // add it to the snake
  248.         GXSetPolygonParts(gDragger.snake1, 0, 0, (gxPolygons *)newPt, 
  249.                             gxBreakNeitherEdit);
  250.         numPts = 3;
  251.     }
  252.     
  253.     // Store the three indices in this order: V, O, U
  254.     gDragger.slavePt[0] = 1;
  255.     gDragger.slavePt[1] = (numPts < 4) ? 2 : (numPts / 2);
  256.     gDragger.slavePt[2] = numPts;
  257.     
  258.     // Reset the dragger geometry
  259.     GXSetShapePoints(gDragger.snake1, gDragger.slavePt[0], 1, &line1.last);
  260.     GXSetShapePoints(gDragger.snake1, gDragger.slavePt[1], 1, &line1.first);
  261.     GXSetShapePoints(gDragger.snake1, gDragger.slavePt[2], 1, &line2.last);
  262.  
  263.     // Now remake the pattern according to the new dragger and redraw it
  264.     RemakeTile();
  265. }
  266.  
  267. Boolean p1_IsVectorPoint(long ptIndex)
  268. {
  269.     return(    ptIndex == gDragger.slavePt[0] ||
  270.             ptIndex == gDragger.slavePt[1] ||
  271.             ptIndex == gDragger.slavePt[2]  );
  272. }
  273.  
  274. void p1_AddedDragPoint(long prevIndex)
  275. {
  276.     // adjust our indexes
  277.     if(prevIndex < gDragger.slavePt[2])
  278.         gDragger.slavePt[2]++;
  279.     if(prevIndex < gDragger.slavePt[1])
  280.         gDragger.slavePt[1]++;
  281. }
  282.  
  283. void p1_RemovedDragPoint(long index)
  284. {
  285.     // adjust our indexes
  286.     gDragger.slavePt[2]--;    // always decrement last point
  287.     if(index < gDragger.slavePt[1])
  288.         gDragger.slavePt[1]--;
  289. }
  290.  
  291.  
  292. ///////////////////////////////////////////////////////////////////////////////////
  293. //    Group pg
  294.  
  295. // Test for a hit on an op shape, tracking the drag and returning true
  296. // if one was hit, false otherwise
  297. Boolean    pg_OpShapeHit(gxPoint *clickPt)
  298. {
  299.     gxHitTestInfo    hitStats;
  300.     gxShape            hitShape, oldShape1, oldShape2;
  301.     gxTransform        xForm;
  302.     long            shapeNum;
  303.     Boolean            arrowHit = false;
  304.     
  305.     // Test the two glide lines for a hit, arrow head first
  306.     for(shapeNum = 0; shapeNum < 2; shapeNum++)
  307.     {
  308.         hitShape = gOpShapes[shapeNum];
  309.         xForm = GXGetShapeTransform(hitShape);
  310.         
  311.         // Test for a hit on the end cap
  312.         GXIgnoreGraphicsNotice(attributes_already_set);
  313.         GXSetTransformHitTest(xForm, gxEndCapPart, kHitTolerance);
  314.         GXPopGraphicsNotice();
  315.  
  316.         // If shape was hit, we're done looking
  317.         if(GXHitTestShape(hitShape, clickPt, &hitStats))
  318.             break;
  319.     }
  320.     
  321.     // if a hit, it was an arrow
  322.     if(shapeNum < 2)
  323.     {
  324.         arrowHit = true;
  325.     }
  326.     else  // Try for a regular line hit
  327.     {
  328.         for(shapeNum = 0; shapeNum < 2; shapeNum++)
  329.         {
  330.             hitShape = gOpShapes[shapeNum];
  331.             xForm = GXGetShapeTransform(hitShape);
  332.             
  333.             // Test for a hit on the geometry
  334.             GXIgnoreGraphicsNotice(attributes_already_set);
  335.             GXSetTransformHitTest(xForm, gxGeometryPart, kHitTolerance);
  336.             GXPopGraphicsNotice();
  337.                 
  338.             // If shape was hit, we're done looking
  339.             if(GXHitTestShape(hitShape, clickPt, &hitStats))
  340.                 break;
  341.         }
  342.     }
  343.     
  344.     // If a shape was hit, track it
  345.     if(shapeNum < 2)
  346.     {
  347.         gxShape        otherShape;
  348.         gxLine        theLine, otherLine;
  349.         gxPoint        anchor, pt, lastPt = *clickPt;
  350.  
  351.         // set up the local references to the shapes
  352.         if(shapeNum == 0)
  353.         {
  354.             hitShape = gOpShapes[0];
  355.             otherShape = gOpShapes[1];
  356.         }
  357.         else            
  358.         {
  359.             hitShape = gOpShapes[1];
  360.             otherShape = gOpShapes[0];
  361.         }
  362.         // Get the "anchor" point (the first point of the other line)
  363.         GXGetLine(otherShape, &otherLine);
  364.         anchor = otherLine.first;
  365.         
  366.         // Create shapes for saving the old positions
  367.         if(!gContRedraw)
  368.         {
  369.             oldShape1 = GXCopyToShape(nil, hitShape);
  370.             oldShape2 = GXCopyToShape(nil, otherShape);
  371.         }
  372.  
  373.         // Follow the drag around while the mouse is down
  374.         while(StillDown())
  375.         {
  376.             // Get the new mouse position and if it's different,
  377.             // adjust the dragged shape
  378.             GXGetViewPortMouse(gViewPort, &pt);
  379.             if(pt.x != lastPt.x || pt.y != lastPt.y)
  380.             {
  381.                 // Save old shapes so we can erase and draw in rapid succession
  382.                 if(!gContRedraw)
  383.                 {
  384.                     GXCopyToShape(oldShape1, hitShape);
  385.                     GXCopyToShape(oldShape2, otherShape);
  386.                     
  387.                     // If constraints are on, erase the dragger before.
  388.                     if(gKeepClosed)
  389.                         EraseAShape(gDragger.snake1);
  390.                 }
  391.                 
  392.                 // Move it
  393.                 pg_DragOpShape(hitShape, otherShape, &pt, &lastPt, &anchor, arrowHit);
  394.                 
  395.                 if(gContRedraw)
  396.                 {
  397.                     // Reset pattern and draw it right now
  398.                     pg_ChangeLattice();
  399.                       OffToScreen();
  400.                 }
  401.                   else
  402.                   {
  403.                     // Erase and draw
  404.                     EraseAShape(oldShape1);
  405.                     GXDrawShape(hitShape);
  406.                     
  407.                     EraseAShape(oldShape2);
  408.                     GXDrawShape(otherShape);
  409.                     
  410.                     // If constraints are on, draw the dragger too.
  411.                     if(gKeepClosed)
  412.                         GXDrawShape(gDragger.snake1);
  413.                   }
  414.               }
  415.             lastPt = pt;
  416.         }
  417.         if(!gContRedraw)
  418.         {
  419.             pg_ChangeLattice(); // Update the pattern
  420.             GXDisposeShape(oldShape1);
  421.             GXDisposeShape(oldShape2);
  422.         }
  423.         return true;
  424.     }
  425.     else // no shape hit
  426.         return false;
  427. }
  428.  
  429. // Moves the op shape and dragger as appropriate
  430. void    pg_DragOpShape(gxShape dragShape, gxShape otherShape, gxPoint *newPt, gxPoint *lastPt, gxPoint *anchor, 
  431.                         Boolean arrowHit)
  432. {
  433.     gxLine    theLine, otherLine;
  434.     
  435.     // First drag the glide shape
  436.     DragGlideShape(dragShape, newPt, lastPt, anchor, constrainH, arrowHit);
  437.     GXGetLine(dragShape, &theLine);
  438.     
  439.     // Make the other one the same length if length changed
  440.     if(arrowHit)
  441.     {
  442.         GXGetLine(otherShape, &otherLine);
  443.         otherLine.last.y = theLine.last.y;
  444.         GXSetLine(otherShape, &otherLine);
  445.     }
  446.     
  447.     // If constraints are on, adjust the dragger too
  448.     if(gKeepClosed)
  449.     {
  450.         GXGetLine(otherShape, &otherLine);
  451.         
  452.         if(dragShape == gOpShapes[0])
  453.         {
  454.             GXSetShapePoints(gDragger.snake1, gDragger.slavePt[0], 1, &theLine.last);
  455.             GXSetShapePoints(gDragger.snake1, gDragger.slavePt[1], 1, &theLine.first);
  456.             
  457.             otherLine.first.x += (otherLine.first.x - theLine.first.x);
  458.             GXSetShapePoints(gDragger.snake1, gDragger.slavePt[2], 1, &otherLine.first);
  459.         }
  460.         else // hit second line, only set 0 and 2
  461.         {
  462.             GXSetShapePoints(gDragger.snake1, gDragger.slavePt[0], 1, &otherLine.last);
  463.             
  464.             theLine.first.x += (theLine.first.x - otherLine.first.x);
  465.             GXSetShapePoints(gDragger.snake1, gDragger.slavePt[2], 1, &theLine.first);
  466.         }
  467.     }
  468. }        
  469.                 
  470.  
  471.  
  472. // Called either to set the default shapes when resetting the tile, or when 
  473. // the symmetry has changed, to convert one lattice type to another.
  474. // Currently only resets to default
  475. void     pg_RemakeOpShapes(Boolean useDefaults)
  476. {
  477.     gxShape    tempShape;
  478.     gxLine    aLine;
  479.     
  480.     if(true /* useDefaults */)
  481.     {
  482.         tempShape = MakeOpShape(glideOp);
  483.         GXMoveShape(tempShape, kStartingOffset, kStartingOffset);
  484.         gOpShapes[0] = GXCopyToShape(nil, tempShape);
  485.         gOpShapes[1] = tempShape;
  486.         GXMoveShape(gOpShapes[1], kStartingGridSize / 2, 0);
  487.     }
  488. }
  489.  
  490. // Set the dragger to the default shape.
  491. void    pg_SetDefaultDragger(gxShape snake)
  492. {
  493.     long        dragPoly[] = {    1,    // number of contours
  494.                                 3,    // number of points
  495.                                 ff(0), ff(64),
  496.                                 ff(0), ff(0),
  497.                                 ff(64), ff(0)    };
  498.                 
  499.  
  500.     // make the starting drag shape
  501.     GXSetPolygons(snake, (gxPolygons *) dragPoly);
  502.     GXMoveShape(snake, kStartingOffset, kStartingOffset);
  503.     
  504.     // Reset the pattern to match the op shapes
  505.     pg_ChangeLattice();
  506. }
  507.  
  508. // Reset the pattern vectors according to the positions of the op shapes
  509. void    pg_ChangeLattice(void)
  510. {
  511.     gxLine    line1, line2;
  512.  
  513.     // Adjust points to define the true unit cell.
  514.     GXGetLine(gOpShapes[0], &line1);
  515.     GXGetLine(gOpShapes[1], &line2);
  516.     gPattern.u.x = 2 * (line2.first.x - line1.first.x);
  517.     gPattern.u.y = 0;
  518.     gPattern.v.x = 0;
  519.     gPattern.v.y = 2 * (line1.last.y - line1.first.y);
  520.     
  521.     // Now remake the pattern according to the new lattice and draw it offscreen
  522.     RemakeTile();
  523. }
  524.  
  525. // Repeat the dragger geometry as necessary to build up the full unit cell.
  526. // Assumes the pattern vectors are set to correctly define the lattice
  527. void    pg_BuildCellShape(gxShape snake)
  528. {
  529.     gxShape    tempShape;
  530.     fixed    dist;
  531.     gxLine    aLine;
  532.     gxPoint    ctr;
  533.     
  534.     // Get the point to reflect around
  535.     GXGetLine(gOpShapes[0], &aLine);
  536.     ctr.x = aLine.first.x;
  537.     ctr.y = 0;
  538. //    GXGetLine(gOpShapes[1], &aLine);
  539. //    if(aLine.first.x < ctr.x)
  540. //        ctr.x = aLine.first.x;
  541.     ctr.x += gPattern.u.x / 2;
  542.     
  543.     // Get the glide distance
  544.     dist = gPattern.v.y / 2;
  545.     
  546.     // Copy the shape, glide reflect it, and add it back in
  547.     tempShape = GXCopyToShape(nil, gTileShape);
  548.     GXMoveShape(tempShape, 0, dist);
  549.     GXScaleShape(tempShape, -ff(1), ff(1), ctr.x, ctr.y);
  550.     GXSetShapeParts(gTileShape, 0, gxSelectToEnd, tempShape, gxBreakLeftEdit);
  551.     GXDisposeShape(tempShape);
  552. }
  553.  
  554. // Force the dragger to describe a closed tile. Much like the p1 version.
  555. void    pg_AttachConstraints(void)
  556. {
  557.     long    numPts;
  558.     gxLine    line1, line2;
  559.  
  560.     // Get the 2 lines
  561.     GXGetLine(gOpShapes[0], &line1);
  562.     GXGetLine(gOpShapes[1], &line2);
  563.     
  564.     // Get the number of points in the snake
  565.     numPts = GXCountShapePoints(gDragger.snake1, 1);
  566.     if(numPts < 3)
  567.     {
  568.         // There can't be only one point, so there must be 2. 
  569.         // so we just need to add 1 point to the end of the snake
  570.         
  571.         gxPoint    newPt[] = {1L, 1L, 0, 0};    // A polygons structure with 1 point
  572.         
  573.         // Get the point into our poly structure
  574.         GXGetShapePoints(gDragger.snake1, numPts, 1, &newPt[1]);
  575.  
  576.         // add it to the snake
  577.         GXSetPolygonParts(gDragger.snake1, 0, 0, (gxPolygons *)newPt, 
  578.                             gxBreakNeitherEdit);
  579.         numPts = 3;
  580.     }
  581.     
  582.     // Store the three indices in this order: V, O, U
  583.     gDragger.slavePt[0] = 1;
  584.     gDragger.slavePt[1] = (numPts < 4) ? 2 : (numPts / 2);
  585.     gDragger.slavePt[2] = numPts;
  586.     
  587.     // Reset the dragger geometry
  588.     GXSetShapePoints(gDragger.snake1, gDragger.slavePt[0], 1, &line1.last);
  589.     GXSetShapePoints(gDragger.snake1, gDragger.slavePt[1], 1, &line1.first);
  590.     line2.first.x += (line2.first.x - line1.first.x);
  591.     GXSetShapePoints(gDragger.snake1, gDragger.slavePt[2], 1, &line2.first); // This is the only difference with p1
  592.  
  593.     // Now remake the pattern according to the new dragger and redraw it
  594.     RemakeTile();
  595. }
  596.  
  597. Boolean pg_IsVectorPoint(long ptIndex)
  598. {
  599.     p1_IsVectorPoint(ptIndex);
  600. }
  601.  
  602. void pg_AddedDragPoint(long prevIndex)
  603. {
  604.     p1_AddedDragPoint(prevIndex);
  605. }
  606.  
  607. void pg_RemovedDragPoint(long index)
  608. {
  609.     p1_RemovedDragPoint(index);
  610. }
  611.  
  612.  
  613. ///////////////////////////////////////////////////////////////////////////////////
  614. //    Group pm
  615.  
  616. // Test for a hit on an op shape, tracking the drag and returning true
  617. // if one was hit, false otherwise
  618. Boolean    pm_OpShapeHit(gxPoint *clickPt)
  619. {
  620.     gxHitTestInfo    hitStats;
  621.     gxShape            hitShape, oldShape;
  622.     gxTransform        xForm;
  623.     long            shapeNum;
  624.     
  625.     // Test the two mirror lines for a hit, arrow head first
  626.     for(shapeNum = 0; shapeNum < 2; shapeNum++)
  627.     {
  628.         hitShape = gOpShapes[shapeNum];
  629.         xForm = GXGetShapeTransform(hitShape);
  630.         
  631.         // Test for a hit on the geometry
  632.         GXIgnoreGraphicsNotice(attributes_already_set);
  633.         GXSetTransformHitTest(xForm, gxGeometryPart, kHitTolerance);
  634.         GXPopGraphicsNotice();
  635.  
  636.         // If shape was hit, we're done looking
  637.         if(GXHitTestShape(hitShape, clickPt, &hitStats))
  638.             break;
  639.     }
  640.     
  641.     // If a shape was hit, track it
  642.     if(shapeNum < 2)
  643.     {
  644.         gxShape        otherShape;
  645.         gxLine        theLine, otherLine;
  646.         gxPoint        anchor, pt, lastPt = *clickPt;
  647.  
  648.         // set up the local references to the shapes
  649.         if(shapeNum == 0)
  650.         {
  651.             hitShape = gOpShapes[0];
  652.             otherShape = gOpShapes[1];
  653.         }
  654.         else            
  655.         {
  656.             hitShape = gOpShapes[1];
  657.             otherShape = gOpShapes[0];
  658.         }
  659.         // Get the "anchor" point (the first point of the other line)
  660.         GXGetLine(otherShape, &otherLine);
  661.         anchor = otherLine.first;
  662.         
  663.         // Create a shape for saving the old position
  664.         if(!gContRedraw)
  665.             oldShape = GXCopyToShape(nil, hitShape);
  666.  
  667.         // Follow the drag around while the mouse is down
  668.         while(StillDown())
  669.         {
  670.             // Get the new mouse position and if it's different,
  671.             // adjust the dragged shape
  672.             GXGetViewPortMouse(gViewPort, &pt);
  673.             if(pt.x != lastPt.x || pt.y != lastPt.y)
  674.             {
  675.                 // Save old shape so we can erase and draw in rapid succession
  676.                 if(!gContRedraw)
  677.                     GXCopyToShape(oldShape, hitShape);
  678.                 
  679.                 // Move it
  680.                 DragLineShape(hitShape, &pt, &lastPt, &anchor, constrainH);
  681.                 
  682.                 if(gContRedraw)
  683.                 {
  684.                     // Reset pattern and draw it right now
  685.                     pm_ChangeLattice();
  686.                       OffToScreen();
  687.                 }
  688.                   else
  689.                   {
  690.                     // Erase and draw
  691.                     EraseAShape(oldShape);
  692.                     GXDrawShape(hitShape);
  693.                   }
  694.               }
  695.             lastPt = pt;
  696.         }
  697.         if(!gContRedraw)
  698.         {
  699.             pm_ChangeLattice(); // Update the pattern
  700.             GXDisposeShape(oldShape);
  701.         }
  702.         return true;
  703.     }
  704.     else // no shape hit
  705.         return false;
  706. }
  707.  
  708. // Called either to set the default shapes when resetting the tile, or when 
  709. // the symmetry has changed, to convert one lattice type to another.
  710. // Currently only resets to default
  711. void     pm_RemakeOpShapes(Boolean useDefaults)
  712. {
  713.     gxShape    tempShape;
  714.     gxLine    aLine;
  715.     
  716.     if(true /* useDefaults */)
  717.     {
  718.         tempShape = MakeOpShape(reflOp);
  719.         GXMoveShape(tempShape, kStartingOffset, kStartingOffset);
  720.         gOpShapes[0] = GXCopyToShape(nil, tempShape);
  721.         gOpShapes[1] = tempShape;
  722.         GXMoveShape(gOpShapes[1], kStartingGridSize, 0);
  723.     }
  724. }
  725.  
  726. // Set the dragger to the default shape.
  727. void    pm_SetDefaultDragger(gxShape snake)
  728. {
  729.     long        dragPoly[] = {    1,    // number of contours
  730.                                 2,    // number of points
  731.                                 ff(0), ff(0),
  732.                                 ff(64), ff(0)    };
  733.                 
  734.  
  735.     // make the starting drag shape
  736.     GXSetPolygons(snake, (gxPolygons *) dragPoly);
  737.     GXMoveShape(snake, kStartingOffset, kStartingOffset);
  738.     
  739.     // Reset the pattern to match the op shapes
  740.     pm_ChangeLattice();
  741. }
  742.  
  743. // Reset the pattern vectors according to the positions of the op shapes
  744. void    pm_ChangeLattice(void)
  745. {
  746.     gxLine    line1, line2;
  747.  
  748.     // Adjust points to define the true unit cell.
  749.     GXGetLine(gOpShapes[0], &line1);
  750.     GXGetLine(gOpShapes[1], &line2);
  751.     gPattern.u.x = 2 * (line2.first.x - line1.first.x);
  752.     gPattern.u.y = 0;
  753.     gPattern.v.x = 0;
  754.     gPattern.v.y = kStartingGridSize;
  755.     
  756.     // Now remake the pattern according to the new lattice and draw it offscreen
  757.     RemakeTile();
  758. }
  759.  
  760. // Repeat the dragger geometry as necessary to build up the full unit cell
  761. void    pm_BuildCellShape(gxShape snake)
  762. {
  763.     gxShape    tempShape;
  764.     gxLine    aLine;
  765.     gxPoint    ctr;
  766.     
  767.     // Get the point to reflect around
  768.     GXGetLine(gOpShapes[0], &aLine);
  769.     ctr.x = aLine.first.x;
  770.     ctr.y = 0;
  771.     ctr.x += gPattern.u.x / 2;
  772.     
  773.     // Copy the shape, reflect it, and add it back in
  774.     tempShape = GXCopyToShape(nil, gTileShape);
  775.     GXScaleShape(tempShape, -ff(1), ff(1), ctr.x, ctr.y);
  776.     GXSetShapeParts(gTileShape, 0, gxSelectToEnd, tempShape, gxBreakLeftEdit);
  777.     GXDisposeShape(tempShape);
  778. }
  779.  
  780. ///////////////////////////////////////////////////////////////////////////////////
  781. //    Group cm
  782.  
  783. // Test for a hit on an op shape, tracking the drag and returning true
  784. // if one was hit, false otherwise
  785. Boolean    cm_OpShapeHit(gxPoint *clickPt)
  786. {
  787.     gxHitTestInfo    hitStats;
  788.     gxShape            hitShape, oldShape;
  789.     gxTransform        xForm;
  790.     long            shapeNum;
  791.     Boolean            arrowHit;
  792.     
  793.     // Test the glide line arrow head for a hit first
  794.     shapeNum = 1;
  795.     hitShape = gOpShapes[shapeNum];
  796.     xForm = GXGetShapeTransform(hitShape);
  797.     
  798.     // Test for a hit on the end cap
  799.     GXIgnoreGraphicsNotice(attributes_already_set);
  800.     GXSetTransformHitTest(xForm, gxEndCapPart, kHitTolerance);
  801.     GXPopGraphicsNotice();
  802.  
  803.     // If shape was hit, log the fact
  804.     if(GXHitTestShape(hitShape, clickPt, &hitStats))
  805.         arrowHit = true;
  806.     else  // Try for a regular line hit
  807.     {
  808.         for(shapeNum = 0; shapeNum < 2; shapeNum++)
  809.         {
  810.             hitShape = gOpShapes[shapeNum];
  811.             xForm = GXGetShapeTransform(hitShape);
  812.             
  813.             // Test for a hit on the geometry
  814.             GXIgnoreGraphicsNotice(attributes_already_set);
  815.             GXSetTransformHitTest(xForm, gxGeometryPart, kHitTolerance);
  816.             GXPopGraphicsNotice();
  817.                 
  818.             // If shape was hit, we're done looking
  819.             if(GXHitTestShape(hitShape, clickPt, &hitStats))
  820.                 break;
  821.         }
  822.     }
  823.     
  824.     // If a shape was hit, track it
  825.     if(shapeNum < 2)
  826.     {
  827.         gxShape        otherShape;
  828.         gxLine        theLine, otherLine;
  829.         gxPoint        anchor, pt, lastPt = *clickPt;
  830.  
  831.         // set up the local references to the shapes
  832.         if(shapeNum == 0)
  833.         {
  834.             hitShape = gOpShapes[0];
  835.             otherShape = gOpShapes[1];
  836.         }
  837.         else            
  838.         {
  839.             hitShape = gOpShapes[1];
  840.             otherShape = gOpShapes[0];
  841.         }
  842.         // Get the "anchor" point (the x coord of the other line, and the y coord of this one)
  843.         GXGetLine(hitShape, &theLine);
  844.         GXGetLine(otherShape, &otherLine);
  845.         anchor.x = otherLine.first.x;
  846.         anchor.y = theLine.first.y;
  847.         
  848.         // Create a shape for saving the old position
  849.         if(!gContRedraw)
  850.             oldShape = GXCopyToShape(nil, hitShape);
  851.  
  852.         // Follow the drag around while the mouse is down
  853.         while(StillDown())
  854.         {
  855.             // Get the new mouse position and if it's different,
  856.             // adjust the dragged shape
  857.             GXGetViewPortMouse(gViewPort, &pt);
  858.             if(pt.x != lastPt.x || pt.y != lastPt.y)
  859.             {
  860.                 // Save old shape so we can erase and draw in rapid succession
  861.                 if(!gContRedraw)
  862.                     GXCopyToShape(oldShape, hitShape);
  863.                 
  864.                 // Move it
  865.                 if(shapeNum == 0)
  866.                     DragLineShape(hitShape, &pt, &lastPt, &anchor, constrainH);
  867.                 else
  868.                     DragGlideShape(hitShape, &pt, &lastPt, &anchor, constrainH,
  869.                                     arrowHit);
  870.                 
  871.                 if(gContRedraw)
  872.                 {
  873.                     // Reset pattern and draw it right now
  874.                     cm_ChangeLattice();
  875.                       OffToScreen();
  876.                 }
  877.                   else
  878.                   {
  879.                     // Erase and draw
  880.                     EraseAShape(oldShape);
  881.                     GXDrawShape(hitShape);
  882.                   }
  883.               }
  884.             lastPt = pt;
  885.         }
  886.         if(!gContRedraw)
  887.         {
  888.             cm_ChangeLattice(); // Update the pattern
  889.             GXDisposeShape(oldShape);
  890.         }
  891.         return true;
  892.     }
  893.     else // no shape hit
  894.         return false;
  895. }
  896.  
  897. // Called either to set the default shapes when resetting the tile, or when 
  898. // the symmetry has changed, to convert one lattice type to another.
  899. // Currently only resets to default
  900. void     cm_RemakeOpShapes(Boolean useDefaults)
  901. {
  902.     gxShape    tempShape;
  903.     gxLine    aLine;
  904.     
  905.     if(true /* useDefaults */)
  906.     {
  907.         tempShape = MakeOpShape(reflOp);
  908.         GXMoveShape(tempShape, kStartingOffset, kStartingOffset);
  909.         gOpShapes[0] = tempShape;
  910.         tempShape = MakeOpShape(glideOp);
  911.         GXMoveShape(tempShape, kStartingOffset + (kStartingGridSize / 2),
  912.                                 kStartingOffset);
  913.         gOpShapes[1] = tempShape;
  914.     }
  915. }
  916.  
  917. // Set the dragger to the default shape.
  918. void    cm_SetDefaultDragger(gxShape snake)
  919. {
  920.     long        dragPoly[] = {    1,    // number of contours
  921.                                 3,    // number of points
  922.                                 ff(0), ff(64),
  923.                                 ff(0), ff(0),
  924.                                 ff(64), ff(0)    };
  925.                 
  926.  
  927.     // make the starting drag shape
  928.     GXSetPolygons(snake, (gxPolygons *) dragPoly);
  929.     GXMoveShape(snake, kStartingOffset, kStartingOffset);
  930.     
  931.     // Reset the pattern to match the op shapes
  932.     cm_ChangeLattice();
  933. }
  934.  
  935. // Reset the pattern vectors according to the positions of the op shapes
  936. void    cm_ChangeLattice(void)
  937. {
  938.     gxLine    line1, line2;
  939.  
  940.     // Adjust points to define the true unit cell.
  941.     GXGetLine(gOpShapes[0], &line1);
  942.     GXGetLine(gOpShapes[1], &line2);
  943.     gPattern.u.x = 4 * (line2.first.x - line1.first.x);
  944.     gPattern.u.y = 0;
  945.     gPattern.v.x = 0;
  946.     gPattern.v.y = 2 * (line2.last.y - line2.first.y);
  947.     
  948.     // Now remake the pattern according to the new lattice and draw it offscreen
  949.     RemakeTile();
  950. }
  951.  
  952. // Repeat the dragger geometry as necessary to build up the full unit cell
  953. void    cm_BuildCellShape(gxShape snake)
  954. {
  955.     gxShape    tempShape;
  956.     gxLine    aLine;
  957.     gxPoint    ctr;
  958.     fixed    dist;
  959.     
  960.     // Get the point to glide reflect around
  961.     GXGetLine(gOpShapes[1], &aLine);
  962.     ctr.x = aLine.first.x;
  963.     ctr.y = 0;
  964.     //ctr.x += gPattern.u.x / 4;
  965.     
  966.     // Get the glide distance
  967.     dist = gPattern.v.y / 2;
  968.             
  969.     // Copy the shape, glide reflect it, and add it back in
  970.     tempShape = GXCopyToShape(nil, gTileShape);
  971.     GXMoveShape(tempShape, 0, dist);
  972.     GXScaleShape(tempShape, -ff(1), ff(1), ctr.x, ctr.y);
  973.     GXSetShapeParts(gTileShape, 0, gxSelectToEnd, tempShape, gxBreakLeftEdit);
  974.     GXDisposeShape(tempShape);
  975.  
  976.     // Then reflect the whole thing
  977.     // Get the point to reflect around
  978.     GXGetLine(gOpShapes[0], &aLine);
  979.     ctr.x = aLine.first.x;
  980.     //ctr.x += gPattern.u.x;
  981.  
  982.     // Copy the shape, reflect it, and add it back in
  983.     tempShape = GXCopyToShape(nil, gTileShape);
  984.     GXScaleShape(tempShape, -ff(1), ff(1), ctr.x, ctr.y);
  985.     GXSetShapeParts(gTileShape, 0, gxSelectToEnd, tempShape, gxBreakLeftEdit);
  986.     GXDisposeShape(tempShape);
  987. }
  988.  
  989.  
  990.